import cv2
import numpy as np

img = cv2.imread("img/circle.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
canny = cv2.Canny(binary, 80, 230)

# method	检测方法，请参见 HoughModes。可用的方法有 HOUGH_GRADIENT 和 HOUGH_GRADIENT_ALT。
# dp	累加器分辨率与图像分辨率的反比。例如，如果 dp=1 ，则累加器与输入图像具有相同的分辨率。如果 dp=2 ，则累加器的宽度和高度是其一半。对于HOUGH_GRADIENT_ALT，推荐的值是 dp=1.5，除非需要检测一些非常小的圆圈。
# minDist	检测到的圆心之间的最小距离。如果参数太小，除了一个真实的相邻圆圈外，还可能错误地检测到多个相邻圆。如果太大，可能会错过一些圆圈。
# 参数1	第一个特定于方法的参数。在 HOUGH_GRADIENT 和 HOUGH_GRADIENT_ALT的情况下，它是传递给 Canny 边缘检测器的两者中较高的阈值（较低的阈值小两倍）。请注意，HOUGH_GRADIENT_ALT使用 Scharr 算法来计算图像导数，因此阈值通常应较高，例如 300 或正常曝光和对比度较高的图像.
# 参数2	第二个特定于方法的参数。在HOUGH_GRADIENT的情况下，它是检测阶段圆心的累加器阈值。它越小，可以检测到的假圆圈就越多。对应于较大的累加器值的圆圈将首先返回。在HOUGH_GRADIENT_ALT算法的情况下，这是圆的“完美度”度量。它越接近 1，算法选择的形状越好的圆圈。在大多数情况下，0.9 应该没问题。如果您想更好地检测小圆圈，您可以将其减少到 0.85、0.8 甚至更低。但随后也尝试限制搜索范围 [minRadius， maxRadius]，以避免许多虚假圆圈.
# minRadius	最小圆半径。
# maxRadius	最大圆半径。如果 <= 0，则使用最大图像尺寸。如果< 0，则返回HOUGH_GRADIENT中心而不找到半径。HOUGH_GRADIENT_ALT始终计算圆半径。
circles = cv2.HoughCircles(canny, cv2.HOUGH_GRADIENT, 2, 10, minRadius=80)

for circle in circles:
    x, y, r = circle[0]
    x = int(x)
    y = int(y)
    r = int(r)
    cv2.circle(img, (x, y), r, (0, 0, 255), 2)

cv2.imshow("img", img)
cv2.waitKey(0)
